home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
byt86oct.arc
/
ALLOC.ARC
/
ALLOC1.MOD
< prev
next >
Wrap
Text File
|
1985-07-12
|
4KB
|
155 lines
IMPLEMENTATION MODULE Alloc1;
(* A simple storage allocator that uses the first-fit strategy.
Copyright 1986 by Jonathan Amsterdam. All Rights Reserved. *)
FROM SYSTEM IMPORT WORD, ADDRESS, TSIZE;
FROM MachineSpecific IMPORT getHeapBottom, getHeapTop, bytesPerWord,
address, cardinal, addrLessThan, writeAddress;
FROM MyTerminal IMPORT fatal;
CONST maxIndex = 32767;
TYPE blockPtr = POINTER TO block;
block = RECORD
size:CARDINAL; (* not including header *)
CASE BOOLEAN OF
TRUE: nextBlock: blockPtr;
| FALSE: contents:ARRAY[0..maxIndex] OF WORD;
END;
END;
VAR heapBottom, heapTop:ADDRESS;
freeList:blockPtr;
blockHeaderSize, minBlockSize:CARDINAL;
PROCEDURE init;
VAR a:ADDRESS;
BEGIN
heapBottom := getHeapBottom();
heapTop := getHeapTop();
freeList := blockPtr(heapBottom);
freeList^.size :=
(cardinal(heapTop - heapBottom) DIV bytesPerWord) - blockHeaderSize;
freeList^.nextBlock := NIL;
blockHeaderSize := TSIZE(CARDINAL);
minBlockSize := TSIZE(blockPtr) + blockHeaderSize;
END init;
PROCEDURE blockSize(blockp:blockPtr):CARDINAL;
BEGIN
RETURN blockp^.size;
END blockSize;
PROCEDURE getWord(blockp:blockPtr; n:CARDINAL):WORD;
BEGIN
IF n < blockp^.size THEN
RETURN blockp^.contents[n];
ELSE
fatal('getWord: out of bounds');
END;
END getWord;
PROCEDURE setWord(blockp:blockPtr; n:CARDINAL; w:WORD);
BEGIN
IF n < blockp^.size THEN
blockp^.contents[n] := w;
ELSE
fatal('setWord: out of bounds');
END;
END setWord;
PROCEDURE allocate(nWords:CARDINAL):blockPtr;
VAR currBlock, prevBlock:blockPtr;
BEGIN
currBlock := freeList;
prevBlock := NIL;
WHILE currBlock <> NIL DO
IF nWords + minBlockSize < currBlock^.size THEN
(* split the block into two, returning the 2nd part *)
DEC(currBlock^.size, nWords+blockHeaderSize);
INC(currBlock, bytesPerWord*(blockHeaderSize + currBlock^.size));
currBlock^.size := nWords;
RETURN currBlock;
ELSIF nWords <= currBlock^.size THEN (* return the whole block *)
link(prevBlock, currBlock^.nextBlock);
RETURN currBlock;
END;
prevBlock := currBlock;
currBlock := currBlock^.nextBlock;
END;
RETURN NIL;
END allocate;
PROCEDURE free(VAR freeBlock:blockPtr);
VAR currBlock, prevBlock:blockPtr;
BEGIN
IF addrBetween(heapBottom, freeBlock, heapTop) THEN
currBlock := freeList;
prevBlock := NIL;
WHILE (currBlock <> NIL) AND addrLessThan(currBlock, freeBlock) DO
prevBlock := currBlock;
currBlock := currBlock^.nextBlock;
END;
IF currBlock = NIL THEN
freeBlock^.nextBlock := NIL;
link(prevBlock, freeBlock);
ELSE (* freeBlock belongs just before currBlock *)
freeBlock^.nextBlock := currBlock;
link(prevBlock, freeBlock);
END;
tryToMerge(prevBlock, freeBlock, currBlock);
freeBlock := NIL;
END;
END free;
PROCEDURE tryToMerge(lowBlock, middleBlock, highBlock:blockPtr);
BEGIN
IF adjacent(middleBlock, highBlock) THEN
merge(middleBlock, highBlock);
END;
IF adjacent(lowBlock, middleBlock) THEN
merge(lowBlock, middleBlock);
END;
END tryToMerge;
PROCEDURE adjacent(lowerBlock, higherBlock:blockPtr):BOOLEAN;
BEGIN
RETURN
(lowerBlock <> NIL) AND
(higherBlock <> NIL) AND
(lowerBlock + address(bytesPerWord*(lowerBlock^.size + blockHeaderSize)) =
higherBlock);
END adjacent;
PROCEDURE merge(lowerBlock, higherBlock:blockPtr);
BEGIN
INC(lowerBlock^.size, higherBlock^.size + blockHeaderSize);
lowerBlock^.nextBlock := higherBlock^.nextBlock;
END merge;
PROCEDURE link(prevBlock, linkBlock:blockPtr);
BEGIN
IF prevBlock = NIL THEN
freeList := linkBlock;
ELSE
prevBlock^.nextBlock := linkBlock;
END;
END link;
PROCEDURE addrBetween(low, middle, high:ADDRESS):BOOLEAN;
BEGIN
RETURN (addrLessThan(low, middle) OR (low = middle)) AND
(addrLessThan(middle, high) OR (middle = high));
END addrBetween;
PROCEDURE getFreeList():blockPtr;
(* for debugging only *)
BEGIN
RETURN freeList;
END getFreeList;
BEGIN
init;
END Alloc1.
reeList(